Работа Бирюковой Надежды Игоревны.

Функциональное программирование. Язык программирования LISP.

2008 г.




На главную


История LISP.
Мифы о языке LISP.
Синтаксис LISPа.
Основные операции.
LISP - язык списков .
Лисп - язык функционального программирования.
Как же написать свою функцию? .
Рекурсивная сущность LISP.
Применения Лиспа.
1. Искусственный интеллект.
2. Компьютерная алгебра.




Введение.

      LISP давно признан одним из великих языков программирования. Однако LISP так и не стал широко распространенным языком. Язык LISP был разработан в Стэнфорде под руководством Дж. Маккарти в начале 60-х годов. Изначально рассчитывалось, что этот язык будет включать средства работы с матрицами, указателями, структурами из указателей и т.д. К моменту создания первых LISP-интерпретаторов в практику работы на ЭВМ стал входить диалоговый режим, а режим интерпретации хорошо вписался в структуру диалоговой обработки. Принципы, которые лежат в основе этого языка программирования: использование единого спискового представления для программ и данных, применение выражений для определения функций, скобочный синтаксис языка.

Основная часть
История LISP.

1958 - Первые публикации Джона Мак-Карти о замысле языка символьной обработки.

1962-1964 - Авторские проекты первых LISP-систем.

1964 - Демонстрация принципиальной решаемости проблем искусственного интеллекта. (Написанная Дж.Вейценбаумом на Лиспе программа-собеседник "Элиза", имитирующая речевое поведение психоаналитика, дала положительный ответ на вопрос о возможности искусственного разума.)

1972-1974 - Разрешение теоретических парадоксов, связанных с бестиповым лямбда-исчислением.

1972-1980 - Стандартизация языка LISP.

1978 - Появление LISP-компьютеров.

1965-1990 - Построение специализированных диалектов Лиспа и создание практичных реализаций для широкого спектра весьма различных применений, включая инженерное проектирование и системы математической обработки информации

1992-2002 - Разработка визуальных и сверхэффективных LISP -систем, таких как CMUCL.

Мифы о языке LISP

      Существует множество так называемых "мифов" о языке Лисп. В основном эти мифы появляются в результате сложности языка и того, что этот язык не очень распространён. Вот наиболее яркие примеры таких произведений:
            {Я не вижу спроса на Лисп-программирование. Спрос бывает разный. Программисты на Лиспе действительно не нужны при разработке бухгалтерских программ. У Лиспа совершенно другая ниша - это язык для решения действительно интересных, а потому сложных задач. Кстати, задачи искусственного интеллекта являются только небольшой областью, в которой Лисп занимает ведущие позиции во всем мире. Программисты на Лиспе являются наиболее тщательно оберегаемыми от внешнего мира интеллектуальными ресурсами крупнейших компаний - именно они разрабатывают программные комплексы стратегического планирования и анализа, а поэтому реклама им не нужна - хорошие заработки и сдувание пылинок гарантированы!
            В Лиспе нет графического интерфейса... Просто потрясающе! Самый первый графический интерфейс, с которого впоследствии были слизаны и Microsoft Windows и MacOS были реализованы именно на Лисп-машине! Никаких проблем в том, чтобы реализовать графический интерфейс и на обычной платформе PC нет - и в этом вы убедитесь прямо сегодня!
            В Лиспе слишком много скобок... Точно так же можно утверждать, что в Паскале слишком часто используется двоеточие, а в Си - точка с запятой.
            На Лиспе никто не пишет... Лисп является исключительно популярной системой при реализации встроенных языков расширения программных систем. Самые популярные примеры - EMACS и Autocad, но пользователям Linux стоит упомянуть также и GIMP. Стоит также упомянуть, что программисты на Лиспе являются предметом постоянной охоты западных рекрутинговых агентств и с завидным постоянством выявленные таланты вывозятся с территории стран СНГ. Впрочем, если учесть, что министерство обороны США объявило Common Lisp официальным языком для построения военных систем искусственного интеллекта, это неудивительно.}1

Синтаксис LISPа.

      Простота синтаксиса LISPa являются одновременно и достоинством и недостатком. Начинающий программист может выучить основные правила синтаксиса за несколько минут, и тогда написание программы в основном сводится (синтаксически) к правильной записи аргументов для каждого вызова функции. Проблемой этого простого синтаксиса являются скобки. В каждом выражении должны быть расставлены все необходимые скобки, а поскольку тело любой функции представляет собой одно гигантское выражение, в определении функции часто накапливается множество уровней вложенных скобок. Такие конструкции чрезвычайно трудно читать и отлаживать, и ошибка в расположении скобок является, по-видимому, наиболее типичной синтаксической ошибкой в языке. К сожалению, неправильное расположение скобок во многих LISP случаях формально не рассматривается, как синтаксическая ошибка. Существует даже шутка: LISP - "Lots of Idiotic Silly Parentheses" (переведите самостоятельно). Логические ошибки такого рода очень трудно найти, а плохая читаемость определений функций удваивает трудность этой задачи.

Основные операции.

      Как уже раньше говорилось, LISP - язык списков. Список в свою очередь состоит из атомов(элементарных объектов) и списков. Числа тоже являются атомами.
      Ввод числа возвращает это же число в качестве результата:

45
==> 45

      Ввод буквы вызовет ошибку, так как буквы являются переменными, и их нельзя использовать, пока им не будет присвоено значение.
A
==> Атом "a" не имеет значения (не связан).

      Для присваивания переменной значения существует функция setq:
(setq a 100)
==> 100
a
==> 100

      Получаем, что функцией "(setq a 100)" мы присвоили переменной a значение 100, а затем функцией "a" запросили её значение.

      Рассмотрим простейшие алгебраические операции над числами.
Функция Plus (или "+") выдаёт сумму всех своих аргументов:
(PLUS 10 30 40 60)
==> 140
(+ 10 30)
==> 40

Функция Difference (или "-") выдаёт разность всех своих аргументов:
(Difference 100 30 40)
==> 30
(- 100 30 40)
==> 30

Функция TIMES (или "*") выдаёт произведение всех своих аргументов:
(TIMES 10 2)
==> 20
(* 2 4 5)
==> 40

Функция DIVIDE (или "/") выдаёт частное от деления первого аргумента на второй:
(DIVIDE 8 4)
==> 2.0
(/ 8 4)
==> 2.0
(\ 8 4)
==> 2

LISP - язык списков.

      В языке LISP существуют списки чисел. Самая распространённая ошибка при присваивании переменной списка:

(setq b (100 10 20 30 40 50))
==> Не найдена функция 100

      Это значит, что язык принимает выражение (100 10 20 30 40 50) за функцию и пытается вычислить её значение. Чтобы LISP "не лез" в список и не вычислял его значения, нужно поставить перед списком '.Указание перед переменной апострофа говорит Lisp задержать вычисление списка или атома, который следует за этим апострофом.
(setq b '(100 10 20 30 40 50))
==> (100 10 20 30 40 50)
b
==> (100 10 20 30 40 50)

      Простейшие операции со списками:
CAR Вычисление головы списка
CDR Вычисление хвоста списка
CAAR (Car (car *))
CDDR (Cdr (Cdr *))
CADR (Car (Cdr *))
CDAR (Cdr (Car *))
CADDR (Car (Cdr (Cdr *)))
CDDDR (Cdr (Cdr (Cdr *)))

      Например:
(car b)
==> 100
(cdr b)
==> (10 20 30 40 50)
(cddr b)
==> (20 30 40 50)

      В LISP существует операция проверки (в Паскале это if) cond:
((cond ((Условие-1) Результат-1)
((Условие-2) Результат-2)
((Условие-n) Результат-n)
(T Результат))

(setq d (car b))
==> 100
(cond ((EQ d 100) 'ДА!!!)
(T 'НЕТ!!!))
==> ДА!!!
(setq d (cadr b))
==> 10
(cond ((EQ d 100) 'ДА!!!)
(T 'НЕТ!!!))
==> НЕТ!!!

Лисп - язык функционального программирования.

      Существует два подхода к созданию программ - процедурное программирование и функциональное программирование.
      В процедурном программировании программист должен разбить алгоритм решения задачи на отдельные элементарные операции и правильно их скомпоновать.
      При функциональном подходе программист пишет функцию (или несколько функций), вычисление которой и обеспечивает решение задачи. Лисп является первым в истории языком функционального программирования. Более молодые языки заимствовали многие идеи, которые впервые были оформлены в Лиспе.

Как же написать свою функцию?

      Для этого существует операция defun

(defun Имя_Функции
(...Список_параметров...)
...Тело функции...
)
      Например, создадим функцию, вычисляющую факториал:
(defun factor
(x)
(cond ((EQ x 0) 1)
((EQ x 1) 1)
( T (* x (factor (- x 1))))))
==> factor
(factor 1)
==> 1
(factor 3)
==> 6
      Данная функция основана на рекурсии.
      Функция называется рекурсивной, если ее определение прямо или косвенно (через другие функции) содержит обращение к самой себе.
      Конечно, аналогичные программы можно написать и на любом другом языке программирования. И они, возможно, будет выглядеть даже более просто. Однако, попытка вычислить факториал числа, большего 30 в таких языках как Паскаль, Basic, C++ приведет к целочисленному переполнению. А в языке LISP целочисленная арифметика имеет неограниченную разрядность, что позволяет рассчитывать факториалы довольно больших чисел:
(factor 100)
=>93326215443944152681699238856266700490715968264381621 46859296389521759999322991560894146397615651828625369 7920827223758251185210916864000000000000000000000000

Рекурсивная сущность LISP.

      Чтобы продемонстрировать рекурсивную сущность Лиспа, рассмотрим пример еще одной функции - подсчет суммы элементов числового списка произвольной длины.
      Процедурный подход к решению этой задачи приводит к следующему решению:
1) завести переменную для будущей суммы и обнулить ее;
2) взять очередной элемент списка и прибавить к значению переменной суммы;
3) если очередной элемент списка - последний, закончть вычисления
4) иначе перейти к п.2
      В Лиспе эту задачу можно решить проще, если взглянуть на математическое определение суммы списка. Это определение имеет вид:
                            | 0 - если список пуст;
Сумма списка = |
                            | Первый элемент + Сумма списка без первого элемента
      Основываясь на этом определении, мы можем сразу же написать нужную нам функцию:
(defun sumlist (x)
       (cond ((null x) 0)
             (T (+ (car x) (sumlist (cdr x))))))
      Эта программа подсчитывает сумму списка любой длины (хотя, естественно, не мгновенно).
      Хочется отметить, что решение аналогичной задачи на языке Паскаль или С не получилось бы столь лаконичным, поскольку потребовалось бы реализовывать список (с использованием указателей).

Применения Лиспа.
1. Искусственный интеллект.

      Интеллект - это способность к обучению.
      Символьная обработка в языке программирования позволяет эффективно работать с переложениями естественного языка, значениями слов и предложений, и на их основе принимать решения и осуществлять другие свойственные человеку способы обращения с данными.
      LISP является наиболее важным языком программирования, используемым в исследованиях по искусственному интеллекту.
      В LISP формы представления программы и обрабатываемых ею данных одинаковы. И то, и другое представляет собой списочную структуру. Поэтому программы способны обрабатывать и преобразовывать другие программы, а так же самих себя.
      С помощью универсального и простого лисповского синтаксиса списка можно легко определять новые формы записи, представления и абстракции. Сама структура языка расширяема и может быть заново определена.
      В LISP используется функциональное программирование, основой которого являются композиция и рекурсия. Программы строятся из логически расчленённых определений функций. В зависимости от системы в LISP можно использовать методы программирования более высокого уровня, таких как объективно-ориентированное программирование, ситуационное, продукционное и логическое программирование.
      В 1964-1966г. Дж. Вейценбаум написал программу для вычислительной машины, с которой можно "беседовать" на английском языке. "Я выбрал для программы лингвистического анализа имя "Элиза", потому что, как и Элизу из знаменитого "Пигмалиона", ее можно было обучать "говорить" все лучше и лучше. Поскольку разговаривать можно лишь о "чем-то", т.е. разговор должен иметь некоторый контекст, программе была придана двухуровневая организация: первый уровень включает лингвистический анализатор, второй - сценарий. Сценарий представляет собой набор правил, примерно таких же, какие можно давать актеру для использования при импровизации на заданную тему... В виде первого эксперимента я задал "Элизе" сценарий, позволяющий ей играть роль (я бы даже сказал - пародировать) психотерапевта-роджерианца, проводящего первичное обследование пациента. Имитировать психотерапевта-роджерианца сравнительно легко, так как его метод в основном состоит в вовлечении пациента в беседу повторением ему его же высказываний...
      "Доктор", как стали называть "Элизу", исполняющую роль психиатра, вскоре приобрел известность в Массачусетском технологическом институте, где эта программа появилась на свет, главным образом, благодаря простоте ее демонстрации..." В заключении Дж.Вейценбаум выдвигает следующие тезисы: "во-первых, между человеком и машиной существуют принципиальные различия; во-вторых, существуют задачи, выполнение которых не следует поручать вычислительным машинам, независимо от того, можно ли добиться, чтобы вычислительные машины их решали".

2. Компьютерная алгебра.

      Компьютерная алгебра - это та часть информатики, которая занимается разработкой, анализом, реализацией и применением алгебраических алгоритмов.
      От других алгоритмов алгебраические отличаются наличием простых формальных описаний, существованием доказательств правильности и асимптотических границ времени выполнения, которые можно получить на основе хорошо развитой математической теории. Кроме того, алгебраические объекты можно точно представить в памяти вычислительной машины, благодаря чему алгебраические преобразования могут быть выполнены без потери точности и значимости. Обычно алгебраические алгоритмы реализуются в программных системах, допускающих ввод и вывод информации в символьных алгебраических обозначениях.
      Выбор языка LISP в качестве языка реализации алгоритмов компьютерной алгебры обусловлено необходимостью динамического управления памятью в связи с проблемой разбухания промежуточных выражений. Так же рекурсивность и списковая структура являются естественными инструментами при автоматизации работы с математическими объектами и операциями.


На главную